<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <title>透视投影视图矩阵</title>
  <link rel="icon" href="https://img.kaikeba.com/kkb_portal_icon.ico">
  <style>
    body {
      margin: 0;
      overflow: hidden;
    }

    #canvas {
      background-color: antiquewhite;
    }
  </style>
</head>

<body>
  <canvas id="canvas"></canvas>
  <!-- 顶点着色器 -->
  <script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform mat4 u_PvMatrix;
    void main(){
    	gl_Position = u_PvMatrix*a_Position;
    }
  </script>
  <script id="fragmentShader" type="x-shader/x-fragment">
    precision mediump float;
    uniform vec4 u_Color;
    void main(){
    	gl_FragColor=u_Color;
    }
  </script>
  <script type="module">
    import { initShaders } from '../jsm/Utils.js';
    import {
      Matrix4, Vector3, Quaternion, Object3D,
      OrthographicCamera, PerspectiveCamera
    } from 'https://unpkg.com/three/build/three.module.js';
    import Poly from './jsm/Poly.js'

    const canvas = document.getElementById('canvas');
    const [viewW, viewH] = [window.innerWidth, window.innerHeight]
    canvas.width = viewW;
    canvas.height = viewH;
    const gl = canvas.getContext('webgl');

    const vsSource = document.getElementById('vertexShader').innerText;
    const fsSource = document.getElementById('fragmentShader').innerText;
    initShaders(gl, vsSource, fsSource);
    gl.clearColor(0.0, 0.0, 0.0, 1.0);

    const eye = new Vector3(1, 0.5, 1)
    const target = new Vector3(0, 0, -2.5)
    const up = new Vector3(0, 1, 0)

    const [fov, aspect, near, far] = [
      45,
      canvas.width / canvas.height,
      1,
      20
    ]
    const camera = new PerspectiveCamera(fov, aspect, near, far)
    camera.position.copy(eye)
    camera.lookAt(target)
    camera.updateWorldMatrix(true)


    //投影视图矩阵
    const pvMatrix = new Matrix4()
      .multiplyMatrices(
        camera.projectionMatrix,
        camera.matrixWorldInverse
      )

    const triangle1 = crtTriangle(
      [1, 0, 0, 1],
      [-0.5, 0, -3]
    )
    const triangle2 = crtTriangle(
      [1, 0, 0, 1],
      [0.5, 0, -3]
    )

    const triangle3 = crtTriangle(
      [1, 1, 0, 1],
      [-0.5, 0, -2]
    )

    const triangle4 = crtTriangle(
      [1, 1, 0, 1],
      [0.5, 0, -2]
    )

    render()

    function render() {
      gl.clear(gl.COLOR_BUFFER_BIT);
      triangle1.init()
      triangle1.draw()
      triangle2.init()
      triangle2.draw()
      triangle3.init()
      triangle3.draw()
      triangle4.init()
      triangle4.draw()
    }

    function crtTriangle(color, [x, y, z]) {
      return new Poly({
        gl,
        source: [
          x, 0.3 + y, z,
          - 0.3 + x, -0.3 + y, z,
          0.3 + x, -0.3 + y, z
        ],
        type: 'TRIANGLES',
        attributes: {
          a_Position: {
            size: 3,
            index: 0
          },
        },
        uniforms: {
          u_Color: {
            type: 'uniform4fv',
            value: color
          },
          u_PvMatrix: {
            type: 'uniformMatrix4fv',
            value: pvMatrix.elements
          },
        }
      })
    }
  </script>
</body>

</html>